// 权限相关操作API接口实现

#include "ApiHandle.h"

#include <mysql++/connection.h>
#include <mysql++/transaction.h>
#include <mysql++/query.h>
#include <rapidjson/writer.h>

#include <cpptools/out.h>
#include <cpptools/stringutil.h>

#include "node.h"
#include "main.h"
#include "PubOpt.pb.h"
#include "PubProtocol.h"

static constexpr const uint64_t kInfo = ct::Out::flagValue({ (uint64_t)out::kApiPmsInfo });
static constexpr const uint64_t kErr = ct::Out::flagValue({ (uint64_t)out::kApiPmsErr });

// 列表
void ApiHandle::permissionList(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;
    int page, pageSize;

    // Step: 必要参数
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Permission list, token.\n");
        return sendHead(pub::err::kParams);
    }

    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);

    if ((it = doc.FindMember("page")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType
        || (page = (int)it->value.GetUint64()) < 1) {
        ct::Out::debug("Error --> Permission list, page.\n");
        return sendHead(pub::err::kParams);
    }
    doc.RemoveMember(it);

    if ((it = doc.FindMember("pageSize")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType
        || (pageSize = (int)it->value.GetUint64()) < 1) {
        ct::Out::debug("Error --> Permission list, pageSize.\n");
        return sendHead(pub::err::kParams);
    }
    doc.RemoveMember(it);

    // Step: 校验权限
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();
    //if (!accSptr->pmsExist(Main::kPmsNamePmsRead)) { // 权限读都允许，但只有读到自己有的权限
    //    return sendHead(pub::err::kPermission);
    //}

    // Step: 从map中取到vector中
    std::vector<pms_t> valid; // 单线程调度,存指针不会出现计数为0情况.

#if 1 // 只给自己拥有的权限
    pms_list_t myPms;
    accSptr->pmsAll(myPms); // 取出此帐号拥有的权限

    // keyword可选查询条件
    if ((it = doc.FindMember("keyword")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        const char* keyword = it->value.GetString();

        for (auto& itr : myPms) {
            if (itr->name().find(keyword) != std::string::npos // 名字或别名任意一个包括指定内容即匹配
                || itr->alias().find(keyword) != std::string::npos) {
                valid.push_back(itr);
            }
        }

    } else {
        for (auto& itr : myPms) {
            valid.push_back(itr);
        }
    }

#else // 给所有权限(早期)
    // keyword可选查询条件
    if ((it = doc.FindMember("keyword")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        const char* keyword = it->value.GetString();
        
        for (auto& itr : Permission::all) {
            if (itr.second->name().find(keyword) != std::string::npos // 名字或别名任意一个包括指定内容即匹配
                || itr.second->alias().find(keyword) != std::string::npos) {
                valid.push_back(itr.second);
            }
        }

    } else {
        for (auto& itr : Permission::all) {
            valid.push_back(itr.second);
        }
    }
#endif

    // Step: 构造JSON并发送
    int total = (size_t)valid.size();
    int i = total - 1 - (page - 1) * pageSize; // 定位到指定的记录数
    int insNums = 0;
    if (i >= total) { i = i % total; }
    //outDebug("valid:size:%zu, i:%d, page:%d, pageSize:%d.\n", valid.size(), i, page, pageSize);

    setHead((uint8_t)pub::err::kSuccess); // 协议头
    rapidjson::Writer<buffer_t> w(buf);

    w.StartObject();
    w.Key("total");
    w.Int(total);
    w.Key("list");
    w.StartArray();

    while (i >= 0 && insNums < pageSize) {
        w.StartObject();

        w.Key("id");
        w.Uint(valid[i]->id());
        w.Key("protect");
        w.Uint(valid[i]->sys());
        w.Key("name");
        w.String(valid[i]->name().data(), (rapidjson::SizeType)valid[i]->name().size());
        w.Key("alias");
        w.String(valid[i]->alias().data(), (rapidjson::SizeType)valid[i]->alias().size());

        insNums++; // 已加入的记录数
        i--;
        w.EndObject();
    }

    w.EndArray();
    w.EndObject();

    session->sendReponse(std::move(buf));
}

void ApiHandle::permissionDetail(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // Step: 必要参数校验
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Permission detail, token.\n");
        return sendHead(pub::err::kParams);
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);

    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Permission detail, id.\n");
        return sendHead(pub::err::kParams);
    }
    uint32_t id = it->value.GetUint();

    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();

    // Step: 校验权限
    if (!accSptr->pmsExist(Main::kPmsNamePmsRead)) {
        return sendHead(pub::err::kPermission);
    }

    // Step：查数据库
    auto funcDb = [id, api = std::move(uptr)] () mutable {
        // 任务线程执行代码开始
        char buf[1024];
        enum Idx {
            NAME,
            ALIAS,
            SYS,
            CREATE_TIME,
            UPDATE_TIME,
            CREATE_ACCOUNT,
            DESCRIBE,
        };
        
        int len = sprintf(buf, "select `name`,`alias`,`sys`,`createTime`,`updateTime`,`createAccount`,`describe` "\
                      "from `%s` where `id`='%u';", Main::kTableNamePms, id);
        ct::Out::debug("sql:%s.\n", buf);

        auto db = Main::dbpool->grab();
        auto query = db->query();
        auto res = query.store(buf, len);

        if (!res) { // 数据库读取错误
            ct::Out::flag(kErr, "Error --> Permission detail, err(%d)(%s), sql(%s).\n", 
                          query.errnum(), query.error(), buf);
            return Main::post([api = std::move(api)] { api->sendHead(pub::err::kInternal); });
        }

        if (res.num_rows() == 0) { // 没有记录
            ct::Out::flag(kErr, "Error --> Permission detail nodata: sql(%s).\n", buf);
            return Main::post([api = std::move(api)] { api->sendHead(pub::err::kAccPwd); });
        }

        // 读取成功
        mysqlpp::Row& row = res[0]; // 只会有一条记录
        rapidjson::Writer<buffer_t> w(api->buf);
        api->setHead((uint8_t)pub::err::kSuccess); // 协议头

        w.StartObject();
        w.Key("name");
        w.String(row[NAME].data(), (rapidjson::SizeType)row[NAME].size());
        w.Key("alias");
        w.String(row[ALIAS].data(), (rapidjson::SizeType)row[ALIAS].size());
        w.Key("describe");
        w.String(row[DESCRIBE].data(), (rapidjson::SizeType)row[DESCRIBE].size());
        w.Key("createAccount");
        w.String(row[CREATE_ACCOUNT].data(), (rapidjson::SizeType)row[CREATE_ACCOUNT].size());
        w.Key("protect");
        w.Uint((unsigned int)row[SYS]);
        w.Key("createTime");
        w.String(row[CREATE_TIME].data(), (rapidjson::SizeType)row[CREATE_TIME].size());
        w.Key("updateTime");
        w.String(row[UPDATE_TIME].data(), (rapidjson::SizeType)row[UPDATE_TIME].size());
        w.EndObject();

        // 推到主线程处理发送
        Main::post([api = std::move(api)] { api->session->sendReponse(std::move(api->buf)); });
    };

    // 新线程中处理数据库操作
    Main::tpool->push(std::move(funcDb)); // 线程池中处理
}

// 权限创建
void ApiHandle::permissionCreate(uptr_t&& uptr) {
    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        string_t name, alias, describe;
        Account::sptr_t accSptr;
        std::vector<uint32_t> pms; // 本帐号需要增加此新建的权限, 存储目前的权限列表
        bool updateDatabase { false }; // 本帐号需要增加此新建的权限, 改数据库, 缓存
        uint32_t newId; // 新创建权限的ID
    };
    
    rapidjson::Document::MemberIterator it;
    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));
    size_t ret;

    // Step: 必要参数
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Permission create, token.\n");
        return sendHead(pub::err::kParams); // token
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);

    if ((it = doc.FindMember("name")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kStringType
        || (ret = it->value.GetStringLength()) > Permission::kNameMaxLen || ret < 1
        || !ct::StringUtil::allow(it->value.GetString(), ".", it->value.GetStringLength(), 1)
        || !strncmp(it->value.GetString(), "acct.", 5)) { // 名称
        ct::Out::debug("Error --> Permission create, name.\n");
        return sendHead(pub::err::kParams);
    }
    p->name.assign(it->value.GetString(), ret);
    doc.RemoveMember(it);

    if ((it = doc.FindMember("alias")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kStringType
        || (ret = it->value.GetStringLength()) > Permission::kAliasMaxLen || ret < 1) {
        ct::Out::debug("Error --> Permission create, alias.\n");
        return sendHead(pub::err::kParams);
    }
    p->alias.assign(it->value.GetString(), ret);
    doc.RemoveMember(it);

    // Step: 可选参数
    if ((it = doc.FindMember("describe")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if (it->value.GetStringLength() > Permission::kDescMaxLen) {
            ct::Out::debug("Error --> Permission create, describe len.\n");
            return sendHead(pub::err::kParams);
        }
        p->describe.assign(it->value.GetString(), it->value.GetStringLength());
    }

    // Step: 校验权限
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();

    if (!accSptr->pmsExist(Main::kPmsNamePmsWrite)) {
        return sendHead(pub::err::kPermission);
    }

    if (!(accSptr->sys() & protect::kAllPms)) { // 非全权限帐号，本帐号需要加入此权限, 先存储当前权限列表
        p->updateDatabase = true; // 需要更新数据库
        p->pms.reserve(accSptr->pms().size());

        for (auto& itr : accSptr->pms()) { // 之前的权限
            p->pms.push_back(itr->id());
        }
    }

    
    //p->req = std::move(req);
    p->accSptr = accSptr;

    // 任务线程函数, 处理数据库
    auto funcDb = [p = std::move(p)] () mutable {
        char buf[4096], tmp1[100], tmp2[100], tmp3[400];
        auto& accSptr = p->accSptr;

        int len = sprintf(buf, "insert into `%s` (`name`,`alias`,`createAccount`,`describe`) values('%s','%s','%s','%s');",
                    Main::kTableNamePms,
                    ct::StringUtil::encodeSqlPtr(p->name.c_str(), tmp1), 
                    ct::StringUtil::encodeSqlPtr(p->alias.c_str(), tmp2),
                    accSptr->name().c_str(),
                    ct::StringUtil::encodeSqlPtr(p->describe.c_str(), tmp3));

        auto db = Main::dbpool->grab();
        mysqlpp::Transaction trans(*db); // 事务，可能需要更新帐号下权限列表，两条sql
        auto query = db->query();
        auto res = query.execute(buf, len);

        ct::Out::debug("sql:%s, rows:%d, insert_id:%d, info:%s.\n", buf, (int)res.rows(), (int)res.insert_id(), res.info());

        if (!res || res.rows() != 1) {
            ct::Out::flag(kErr, "Error --> Create pms, err(%d)(%s), sql(%s).\n", 
                          query.errnum(), query.error(), buf);
            // 回复错误，1062为重复主键错误，表示重名了
            return Main::post([p = std::move(p), err = query.errnum() == 1062 ? pub::err::kExist : pub::err::kInternal] { 
                p->api->sendHead(err); 
            });
        }

        p->newId = (uint32_t)res.insert_id();
        if (p->updateDatabase) { // 非全权限帐号，本帐号需要加入此权限，更新数据库此帐号
            int ret, len = sprintf(buf, "update `%s` set `pms`='[", Main::kTableNameAccount);

            for (auto& itr : p->pms) { // 之前的权限
                ret = sprintf(buf+len, "%u,", itr);
                len += ret;
            }

            ret = sprintf(buf+len, "%u]' where `account`='%s';", p->newId, accSptr->name().c_str()); // 加上本次的新建的权限ID
            len += ret;
            auto res = query.execute(buf, len);

            if (!res || res.rows() != 1) {
                ct::Out::flag(kErr, "Error --> Create pms, err(%d)(%s), sql(%s).\n",
                              query.errnum(), query.error(), buf);
                return Main::post([p = std::move(p)] { p->api->sendHead(pub::err::kInternal); });
            }
            ct::Out::debug("sql:%s, rows:%d, info:%s.\n", buf, (int)res.rows(), res.info());
        }

        trans.commit(); // 执行到此没失败，提交数据库事务

        // 推送到主线程执行函数，处理节点缓存
        auto funcMain = [p = std::move(p)] {
            auto& accSptr = p->accSptr;
            auto& api= p->api;
            auto pmsNode = new Permission(p->newId, 0, std::move(p->name), std::move(p->alias)); // 创建新节点

            // 当前帐号非全权限帐号, 此帐号节点需要加入此权限
            if (p->updateDatabase) {
                accSptr->pmsAdd(pmsNode);
            }

            // 日志
            pub::PbOpt pb;
            pb.set_account(accSptr->name());
            pb.set_time((uint32_t)time(nullptr));
            pb.set_opt(api->opt());
            std::string remark("(name:" + pmsNode->name() + ")");
            if (!pmsNode->alias().empty()) { // p里面name和alias已经被move到pmsSptr里了
                remark += "(alias:" + pmsNode->alias() + ")";
            }
            if (!p->describe.empty()) {
                remark += "(desc:" + p->describe + ")";
            }
            pb.set_remark(remark);
            pb.set_team(accSptr->team());
            pb.set_target_id(pmsNode->id());
            Main::sendLog(pb, pub::log::kOpt);

            // 回复请求
            api->sendHead(pub::err::kSuccess);
        };

        return Main::post(std::move(funcMain)); // 推送到主线程处理后续（节点缓存，全局列表等）
    };

    // 新线程中处理数据库操作
    Main::tpool->push(std::move(funcDb)); // 线程池中处理
}

// 权限更新
void ApiHandle::permissionUpdate(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // token与权限
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Permission update, token.\n");
        return sendHead(pub::err::kParams);
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);
    
    auto tokenOpt = Token::find(token); 
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();
    if (!accSptr->pmsExist(Main::kPmsNamePmsWrite)) {
        return sendHead(pub::err::kPermission);
    }

    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        enum Flag : uint32_t { NAME = 1, ALIAS = 2, DESCRIBE = 4, };
        Account::sptr_t accSptr;
        string_t name, alias, describe;
        uint32_t flag { 0 };
        uint32_t targetId;
    };

    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));

    // Step: 校验目标
    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) { // 目标id
        ct::Out::debug("Error --> Permission update, id.\n");
        return sendHead(pub::err::kParams);
    }
    p->targetId = it->value.GetUint();
    doc.RemoveMember(it);

    auto pmsNode = Permission::find(p->targetId);
    if (!pmsNode) {
        return sendHead(pub::err::kNotFound);
    }
    
    if (pmsNode->sys() & protect::kNoMod) { // 是否不可修改
        ct::Out::debug("Error --> Permission update, protected.\n");
        return sendHead(pub::err::kPermission);
    }

    // 要修改的参数
    if ((it = doc.FindMember("name")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if (it->value.GetStringLength() > Permission::kNameMaxLen
            || it->value.GetStringLength() < 1
            || !ct::StringUtil::allow(it->value.GetString(), ".", it->value.GetStringLength(), 1)
            || !strncmp(it->value.GetString(), "acct.", 5)) {
            ct::Out::debug("Error --> Permission update, name.\n");
            return sendHead(pub::err::kParams);
        }
        if (pmsNode->name() != it->value.GetString()) { // 不相同
            p->flag |= (uint32_t)Info::NAME;
            p->name.assign(it->value.GetString(), it->value.GetStringLength());
        }
    }

    if ((it = doc.FindMember("alias")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if (it->value.GetStringLength() > Permission::kAliasMaxLen) {
            ct::Out::debug("Error --> Permission update, alias len.\n");
            return sendHead(pub::err::kParams);
        }
        if (pmsNode->alias() != it->value.GetString()) { // 不相同
            p->flag |= (uint32_t)Info::ALIAS;
            p->alias.assign(it->value.GetString(), it->value.GetStringLength());
        }
    }

    if ((it = doc.FindMember("describe")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if (it->value.GetStringLength() > Permission::kDescMaxLen) {
            ct::Out::debug("Error --> Permission update, describe len.\n");
            return sendHead(pub::err::kParams);
        }
        p->flag |= (uint32_t)Info::DESCRIBE;
        p->describe.assign(it->value.GetString(), it->value.GetStringLength());
    }

    if (!p->flag) { // 一个参数也没改
        ct::Out::debug("Error --> Permission update, modify 0.\n");
        return sendHead(pub::err::kSuccess);
    }

    p->accSptr = accSptr;

    // 数据库操作函数(任务线程)
    auto funcDb = [p = std::move(p)] () mutable {
        char buf[1024], tmp[400];
        int ret, len = sprintf(buf, "update `%s` set ", Main::kTableNamePms);

        if (p->flag & (uint32_t)Info::NAME) { // name
            ret = sprintf(buf+len, "`name`='%s',", ct::StringUtil::encodeSqlPtr(p->name.c_str(), tmp));
            len += ret;
        }

        if (p->flag & (uint32_t)Info::ALIAS) { // alias
            ret = sprintf(buf + len, "`alias`='%s',", ct::StringUtil::encodeSqlPtr(p->alias.c_str(), tmp));
            len += ret;
        }

        if (p->flag & (uint32_t)Info::DESCRIBE) { // describe
            ret = sprintf(buf + len, "`describe`='%s',", ct::StringUtil::encodeSqlPtr(p->describe.c_str(), tmp));
            len += ret;
        }

        ret = sprintf(buf+len, "`updateTime`=now() where `id`=%u;", p->targetId);
        len += ret;

        auto db = Main::dbpool->grab();
        auto query = db->query();
        auto res = query.execute(buf, len);
        ct::Out::debug("sql:%s, rows:%d.\n", buf, (int)res.rows());

        if (!res || res.rows() != 1) {
            ct::Out::flag(kErr, "Error --> Update pms, err(%d)(%s), sql(%s).\n",
                          query.errnum(), query.error(), buf);
            return Main::post([p = std::move(p), err = query.errnum() == 1062 ? pub::err::kExist : pub::err::kNotFound] { 
                p->api->sendHead(err); 
            });
        }

        // 节点缓存操作函数(主线程)
        auto funcMain = [p = std::move(p)] {
            auto& api= p->api;
            auto& accSptr = p->accSptr;
            auto pmsNode = Permission::find(p->targetId); // 再次查找节点,不能使用主线程传入,可能在数据库线程时被删
            if (pmsNode) {
                std::string remark;
                remark.reserve(400);

                if (p->flag & (uint32_t)Info::NAME) { // 构造日志备注信息并更新缓存
                    remark += "(name:" + p->name + ")";
                    auto nh = Permission::allName.extract(pmsNode->name()); // 全局map key修改
                    nh.key() = p->name;
                    Permission::allName.insert(std::move(nh)); // 再次加入
                    pmsNode->name(std::move(p->name));
                }
                if (p->flag & (uint32_t)Info::ALIAS) { 
                    remark += "(alias:" + p->alias + ")";
                    pmsNode->alias(std::move(p->alias));
                }
                if (p->flag & (uint32_t)Info::DESCRIBE) {
                    remark += "(desc:" + p->describe + ")";
                }

                // 日志
                pub::PbOpt pb;
                pb.set_account(accSptr->name());
                pb.set_time((uint32_t)time(nullptr));
                pb.set_opt(api->opt());
                pb.set_remark(remark);
                pb.set_team(accSptr->team());
                pb.set_target_id(pmsNode->id());
                Main::sendLog(pb, pub::log::kOpt);
            }

            api->sendHead(pub::err::kSuccess); // 回复
        };

        Main::post(std::move(funcMain)); // 推送回主线程处理节点并回复
    };

    Main::tpool->push(std::move(funcDb)); // 推送到任务线程处理
}

// 权限删除
void ApiHandle::permissionDelete(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // Step: 必要参数
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Permission delete, token.\n");
        return sendHead(pub::err::kParams);
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);

    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) { // 目标id
        ct::Out::debug("Error --> Permission delete, id.\n");
        return sendHead(pub::err::kParams);
    }
    uint32_t id = it->value.GetUint();

    // Step: 校验权限
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();

    if (!accSptr->pmsExist(Main::kPmsNamePmsWrite)) {
        return sendHead(pub::err::kPermission);
    }

    // Step: 校验目标
    auto pmsNode = Permission::find(id);
    if (!pmsNode) {
        return sendHead(pub::err::kNotFound);
    }

    if (pmsNode->sys() & protect::kNoDel) { // 是否不可删除
        ct::Out::debug("Error --> Permission delete, protected.\n");
        return sendHead(pub::err::kPermission);
    }

    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        Account::sptr_t accSptr;
        uint32_t targetId;
    };

    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));
    p->targetId = id;
    p->accSptr = accSptr;

    // 数据库操作函数(任务线程)
    auto funcDb = [p = std::move(p)] () mutable {
        char buf[1024];
        int len = sprintf(buf, "delete from `%s` where `id`=%u;", Main::kTableNamePms, p->targetId);

        auto db = Main::dbpool->grab();
        auto query = db->query();
        auto res = query.execute(buf, len);
        ct::Out::debug("sql:%s, rows:%d.\n", buf, (int)res.rows());

        if (!res || res.rows() != 1) {
            ct::Out::flag(kErr, "Error --> Delete pms, err(%d)(%s), sql(%s).\n",
                          query.errnum(), query.error(), buf);
            return Main::post([p = std::move(p)] { p->api->sendHead(pub::err::kNotFound); });
        }

        // 节点缓存操作函数(主线程)
        auto funcMain = [p = std::move(p)] {
            auto& api= p->api;
            auto pmsNode = Permission::find(p->targetId); // 再次查找,防止DB操作期间被删除
            if (pmsNode) {
                auto& accSptr = p->accSptr;

                // 日志
                pub::PbOpt pb;
                pb.set_account(accSptr->name());
                pb.set_time((uint32_t)time(nullptr));
                pb.set_opt(api->opt());
                pb.set_team(accSptr->team());
                pb.set_target_id(pmsNode->id());
                Main::sendLog(pb, pub::log::kOpt);
                delete pmsNode; // 析构,自动从全局列表中删除,自动从角色,帐号节点中删除
            }
            api->sendHead(pub::err::kSuccess); // 回复
        };

        Main::post(std::move(funcMain)); // 推送回主线程处理节点并回复
    };

    Main::tpool->push(std::move(funcDb)); // 推送到任务线程处理
}

void ApiHandle::permissionIdNames(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // Step: 必要参数校验
    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kArrayType) {
        ct::Out::debug("Error --> permission id names, ids.\n");
        return sendHead(pub::err::kParams);
    }

    auto arr = it->value.GetArray();

    setHead((uint8_t)pub::err::kSuccess); // 协议头
    rapidjson::Writer<buffer_t> w(buf);

    w.StartArray();
    uint32_t id;
    pms_t pms;

    for (auto& itr : arr) {
        if (itr.GetType() != rapidjson::kNumberType) {
            continue;
        }

        id = (uint32_t)itr.GetInt64();
        pms = Permission::find(id);

        if (pms) {
            w.StartObject();
            w.Key("id");
            w.Uint(id);
            w.Key("name");
            w.String(pms->name().data(), (rapidjson::SizeType)pms->name().size());
            w.EndObject();
        }
    }

    w.EndArray();
    session->sendReponse(std::move(buf));
}